package org.beetl.sql.core.mapping;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.beetl.sql.core.BeetlSQLException;
import org.beetl.sql.core.HumpNameConversion;
import org.beetl.sql.core.NameConversion;
import org.beetl.sql.core.SQLManager;

/**
 * Pojo处理器，负责转换
 * 
 * @author: suxj
 */
public class BeanProcessor {

 private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<Class<?>, Object>();
 private final Map<String, String> columnToPropertyOverrides;
 protected static final int PROPERTY_NOT_FOUND = -1;
 private NameConversion nc = new HumpNameConversion();

 // 基本类型
 static {
  primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
  primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
  primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
  primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
  primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
  primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
  primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
  primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
 }

 SQLManager sm;
 String dbName;

 protected BeanProcessor() {
  this(new HashMap<String, String>());// 为{} 非null
 }

 public BeanProcessor(NameConversion nc, SQLManager sm) {
  this();
  this.nc = nc;
  this.sm = sm;
  this.dbName = sm.getDbStyle().getName();
 }

 protected BeanProcessor(Map<String, String> columnToPropertyOverrides) {
  super();
  if (columnToPropertyOverrides == null) {
   throw new IllegalArgumentException("columnToPropertyOverrides map cannot be null");
  }
  this.columnToPropertyOverrides = columnToPropertyOverrides;
 }

 /**
  * 将ResultSet映射为一个POJO对象
  * 
  * @param rs
  * @param type
  * @return
  * @throws SQLException
  */
 public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {
  // ResultSetMetaData resultSetMetaData = rs.getMetaData();
  // return
  // this.getBuilder().newFactory(type).newResultSetHandler(resultSetMetaData).handle(rs);
  try {
   return (T) PojoResultSetRowMapperCache.get(type, false).extractData(rs);
  } catch (Exception e) {
   throw new SQLException(e.getMessage());
  }
 }

 /**
  * 将ResultSet映射为一个List&lt;POJO&gt;集合
  * 
  * @param rs
  * @param type
  * @return
  * @throws SQLException
  */
 public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException {
  List<T> results = new ArrayList<T>();
  while (rs.next()) {
   results.add(this.toBean(rs, type));
  }
  return results;
 }

 /**
  * 将rs转化为Map&lt;String ,Object&gt;
  * 
  * @param c
  * @param rs
  * @return
  * @throws SQLException
  */
 public Map<String, Object> toMap(Class<?> c, ResultSet rs) throws SQLException {

  Map<String, Object> result = new CaseInsensitiveHashMap();
  ResultSetMetaData rsmd = rs.getMetaData();
  int cols = rsmd.getColumnCount();
  // String tableName = nc.getTableName(c);
  for (int i = 1; i <= cols; i++) {

   String columnName = rsmd.getColumnLabel(i);
   if (null == columnName || 0 == columnName.length()) {
    columnName = rsmd.getColumnName(i);
   }

   // 通过ResultSetMetaData类，可判断该列数据类型
   if (columnName.equals("BLOB")) {
    java.sql.Blob bb = rs.getBlob(i);
    byte[] b = bb.getBytes(1, (int) bb.length());

    // 将结果放到Map中
    // TODO 是该放String还是byte[]
    // result.put(this.nc.getPropertyName(c,columnName), new String(b,
    // "utf-8"));
    // result.put(this.nc.getPropertyName(c,columnName), b);

    // rs.getObject()在取Blob的时候会是乱码~
    result.put(this.nc.getPropertyName(c, columnName), rs.getObject(i));
   } else {
    // 不是则按原来逻辑运算
    result.put(this.nc.getPropertyName(c, columnName), rs.getObject(i));
   }
  }

  return result;
 }

 /**
  * 忽略key大小写
  * 
  * @author Administrator
  *
  */
 private static class CaseInsensitiveHashMap extends LinkedHashMap<String, Object> {

  private static final long serialVersionUID = 9178606903603606031L;

  private final Map<String, String> lowerCaseMap = new HashMap<String, String>();

  public boolean containsKey(Object key) {
   Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
   return super.containsKey(realKey);
  }

  public Object get(Object key) {
   Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
   return super.get(realKey);
  }

  public Object put(String key, Object value) {

   /*
    * 保持map和lowerCaseMap同步 在put新值之前remove旧的映射关系
    */
   Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
   Object oldValue = super.remove(oldKey);
   super.put(key, value);
   return oldValue;
  }

  public void putAll(Map<? extends String, ?> m) {
   for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
    this.put(key, value);
   }
  }

  public Object remove(Object key) {
   Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
   return super.remove(realKey);
  }
 }

 /**
  * 反射对象
  * 
  * @param c
  * @return
  * @throws SQLException
  */
 protected <T> T newInstance(Class<T> c) throws SQLException {

  try {
   return c.newInstance();

  } catch (InstantiationException e) {
   throw new BeetlSQLException(BeetlSQLException.OBJECT_INSTANCE_ERROR, e);

  } catch (IllegalAccessException e) {
   throw new BeetlSQLException(BeetlSQLException.OBJECT_INSTANCE_ERROR, e);
  }

 }

}
